/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-06-15     xingwenbo       the first version
 */
#include "user_queue.h"

uint16_t user_queue_u8_get_size(struct user_queue_u8 *queue)
{
    if(queue->end >= queue->head)
        return(queue->end - queue->head);
    else
        return(queue->end + queue->len - queue->head);
}

uint8_t user_queue_u8_is_full(struct user_queue_u8 *queue)
{
    return(user_queue_u8_get_size(queue) == (queue->len - 1));
}

uint8_t user_queue_u8_is_empty(struct user_queue_u8 *queue)
{
    return (queue->end == queue->head);
}

void user_queue_u8_init(struct user_queue_u8 *queue,uint8_t *buf,uint16_t len)
{
    queue->buf = buf;
    queue->len = len;
    queue->head = 0;
    queue->end = 0;
}

void user_queue_u8_putchar(struct user_queue_u8 *queue,uint8_t data)
{
    if(!user_queue_u8_is_full(queue))
    {
        queue->buf[queue->end++] = data;
        if(queue->end == queue->len)
            queue->end = 0;
    }
}

uint16_t user_queue_u8_put(struct user_queue_u8 *queue,uint8_t *data,uint16_t length)
{
    if(!user_queue_u8_is_full(queue))
    {
        uint16_t size = user_queue_u8_get_size(queue);
        if (size < length)
            length = size;
        if (queue->len - queue->end > length)
        {
            rt_memcpy(&queue->buf[queue->end], &data[0], length);
            queue->end += length;
        }
        else
        {
            rt_memcpy(&queue->buf[queue->end],
                    &data[0],
                    queue->len - queue->end);

            rt_memcpy(&queue->buf[0],
                    &data[queue->len - queue->end],
                    length - (queue->len - queue->end));
            queue->end = length - (queue->len - queue->end);
        }
        return length;
    }
    else
        return 0;
}
uint16_t user_queue_u8_get(struct user_queue_u8 *queue,uint8_t *data,uint16_t length)
{
    if(!user_queue_u8_is_empty(queue))
    {
        uint16_t size = user_queue_u8_get_size(queue);
        if (size < length)
            length = size;
        if (queue->len - queue->head > length)
        {
            rt_memcpy(&data[0], &queue->buf[queue->head], length);
            queue->head += length;
        }
        else
        {
            rt_memcpy(&data[0],
                   &queue->buf[queue->head],
                   queue->len - queue->head);

            rt_memcpy(&data[queue->len - queue->head],
                   &queue->buf[0],
                   length - ( queue->len - queue->head));

            queue->head = length - ( queue->len - queue->head);
        }

        return length;
    }
    else
        return 0;
}
uint8_t  user_queue_u8_getchar(struct user_queue_u8 *queue)
{
     uint8_t temp;
     if(!user_queue_u8_is_empty(queue))
     {
         temp = queue->buf[queue->head++];
        if(queue->head == queue->len)
            queue->head = 0;
     }
     return temp;
}
uint8_t  user_queue_u8_readchar(struct user_queue_u8 *queue,uint16_t offset)
{
     uint8_t temp;
     uint16_t offset_temp = offset;
     uint16_t head_temp;

     if(!user_queue_u8_is_empty(queue))
     {
        if(offset_temp < (queue->len - queue->head))
        {
            temp = queue->buf[queue->head + offset_temp];
        }
        else
        {
            head_temp = (offset_temp - (queue->len - queue->head)) % queue->len;
            temp = queue->buf[head_temp];
        }
        return temp;
     }
}

void user_queue_u8_headmove(struct user_queue_u8 *queue,int offset_len)
{
    if (offset_len >= 0)
    {
        for (int i = 0; i < offset_len; i++)
        {
            queue->head++;
            if(queue->head == queue->len)
                queue->head = 0;
        }
    }
    else
    {
        for (int i = 0; i > offset_len; i--)
        {
            if(queue->head == 0)
            {
                queue->head = queue->len - 1;
            }
            else
            {
                queue->head--;
            }
        }
    }
}
void user_queue_u8_endmove(struct user_queue_u8 *queue,int offset_len)
{
    if (offset_len >= 0)
    {
        for (int i = 0; i < offset_len; i++)
        {
            queue->end++;
            if(queue->end == queue->len)
                queue->end = 0;
        }

    }
    else
    {
        for (int i = 0; i > offset_len; i--)
        {
            if(queue->end == 0)
            {
                queue->end = queue->len - 1;
            }
            else
            {
                queue->end--;
            }

        }
    }
}
void user_queue_u8_clear(struct user_queue_u8 *queue)
{
    queue->head = queue->end;
}
